﻿using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.IO;
using System.IO.Pipes;
using System.Linq;
using System.Net;
using System.Net.Quic;
using System.Net.Security;
using System.Net.Sockets;
using System.Security.Cryptography.X509Certificates;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
using UMC.Data;
using UMC.Host;
using UMC.Net;
using UMC.ITME.Entities;
using UMC.Web;
using System.Text.RegularExpressions;
using System.Net.NetworkInformation;
using Microsoft.VisualBasic;
using System.Formats.Cbor;
using System.Linq.Expressions;

namespace UMC.ITME
{

    class HttpMimeServier : IDoWorker, IStringSubscribe
    {
        static String _Server = Dns.GetHostName();
        public static String Server => _Server;

        X509Certificate _certificate;

        X509Certificate DefaultCertificate
        {
            get
            {
                if (this._certificate == null)
                {
                    _certificate = X509Certificate2.CreateFromPem(CertKey, PrivateKey);
                }

                return _certificate;
            }
        }
        X509Certificate ServerCertificateSelectionCallback(object sender, string hostName)
        {
            if (String.IsNullOrEmpty(hostName) == false)
            {
                if (Certificater.Certificates.TryGetValue(hostName, out var x509Certificate))
                {
                    return x509Certificate.Certificate ?? DefaultCertificate;
                }
                else
                {
                    var l = hostName.IndexOf('.');
                    if (l > 0)
                    {
                        var cName = "*" + hostName.Substring(l);
                        if (Certificater.Certificates.TryGetValue(cName, out var x509))
                        {
                            return x509.Certificate ?? DefaultCertificate;
                        }
                        else
                        {

                            var certs = HotCache.Find(new SiteCert { Domain = new StringValue(hostName) }, "Domain", new StringValue[] { new StringValue(cName) });
                            if (certs?.Length > 0)
                            {
                                var cert = certs[0];

                                if (cert.PrivateKey.IsEmpty() && certs.Length > 1)
                                {
                                    cert = certs[1];
                                }
                                if (cert.PrivateKey.IsEmpty() == false && cert.PublicKey.IsEmpty() == false)
                                {
                                    try
                                    {
                                        var x5092 = X509Certificate2.CreateFromPem(cert.PublicKey.UTF8(), cert.PrivateKey.UTF8());
                                        Certificater.Certificates[cert.Domain.UTF8()] = new Certificater(cert.Domain.UTF8(), x5092);

                                        return x5092;
                                    }
                                    catch
                                    {
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return DefaultCertificate;
        }

        public SslServerAuthenticationOptions sslServerAuthentication;
        Dictionary<int, Socket[]> _host = new Dictionary<int, Socket[]>();
        HashSet<HttpSocks5> _repost = new HashSet<HttpSocks5>(HttpSocks5.EqualityComparer);
        Socket[] BindSocket(int port, EventHandler<SocketAsyncEventArgs> Completed)
        {
            if (Socket.OSSupportsIPv6)
            {

                var socket = new Socket(AddressFamily.InterNetworkV6, SocketType.Stream, ProtocolType.Tcp);

                socket.Bind(new IPEndPoint(IPAddress.IPv6Any, port));
                socket.Listen(512);
                SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                eventArgs.Completed += Completed;
                socket.AcceptAsync(eventArgs);


                var socket2 = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket2.Bind(new IPEndPoint(IPAddress.Any, port));
                socket2.Listen(512);
                eventArgs = new SocketAsyncEventArgs();
                eventArgs.Completed += Completed;
                socket2.AcceptAsync(eventArgs);
                return new Socket[] { socket, socket2 };

                // return new Socket[] { socket };
            }
            else
            {

                var socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                socket.Bind(new IPEndPoint(IPAddress.Any, port));
                socket.Listen(512);
                SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                eventArgs.Completed += Completed;
                socket.AcceptAsync(eventArgs);
                return new Socket[] { socket };
            }
        }
        List<String> _urls = new List<string>();
        string Config(ProviderConfiguration hosts)
        {
            repostIP = 0;
            UMC.ITME.WebServlet.AuthPre = new StringValue(UMC.Data.WebResource.Instance().Provider["auth"]);

            UMC.ITME.WebServlet.IsHttps = UMC.Data.WebResource.Instance().Provider["scheme"] == "https";
            UMC.ITME.WebServlet.MainDomain = UMC.Data.WebResource.Instance().Provider["domain"] ?? "localhost";
            _urls.Clear();

            var host = new Dictionary<int, Socket[]>();
            var sb = new StringBuilder();
            foreach (var p in hosts.Providers)
            {
                switch (p.Type)
                {
                    case "https":
                        {
                            int port = Utility.IntParse(p.Attributes["port"], 443);

                            try
                            {
                                if (_host.ContainsKey(port) == false)
                                {

                                    if (host.ContainsKey(port) == false)
                                    {
                                        host[port] = BindSocket(port, Https);
                                    }
                                }
                                else
                                {
                                    host[port] = _host[port];
                                    _host.Remove(port);
                                }

                                _urls.Add($"https://*:{port}");
                            }
                            catch (Exception ex)
                            {
                                sb.Append($"Port:{port} {ex.Message};");
                            }
                        }
                        break;
                    case "dns":
                        {
                            int bindPort = Utility.IntParse(p.Attributes["port"], 53);
                            var ipAddresses = new List<IPAddress>();
                            var ipSer = p.Attributes["server"];//?.Split(',', ' ');
                            if (String.IsNullOrEmpty(ipSer) == false)
                            {
                                var ipSers = ipSer.Split(',', ' ');
                                foreach (var ip in ipSers)
                                {
                                    if (IPAddress.TryParse(ip, out var address))
                                    {
                                        ipAddresses.Add(address);
                                    }
                                }
                            }
                            if (ipAddresses.Count == 0)
                            {
                                ipAddresses.Add(IPAddress.Loopback);
                            }

                            DnsServer.Addresses = ipAddresses.ToArray();

                            if (_host.ContainsKey(bindPort) == false)
                            {
                                try
                                {
                                    if (host.ContainsKey(bindPort) == false)
                                    {
                                        var list = new List<Socket>();
                                        var dns = new DnsServer();
                                        list.AddRange(dns.Bind(bindPort));
                                        list.AddRange(BindSocket(bindPort, dns.Http));
                                        host[bindPort] = list.ToArray();
                                        _urls.Add($"dns://*:{bindPort}");
                                    }
                                }
                                catch (Exception ex)
                                {
                                    sb.Append($"DNS:{bindPort} {ex.Message};");

                                }
                            }
                        }
                        break;

                    case "proxy":
                        {

                            var point = p.Attributes["repost"];
                            if (String.IsNullOrEmpty(point) == false)
                            {
                                var prs = point.Split(':');
                                if (IPAddress.TryParse(prs[0], out var address))
                                {
                                    repostIP = BitConverter.ToInt32(address.GetAddressBytes());//new IPEndPoint(address, prs.Length > 1 ? Utility.IntParse(prs[1], 443) : 443);
                                }
                            }
                            int port = Utility.IntParse(p.Attributes["port"], -1);
                            if (port > 5000 && port < IPEndPoint.MaxPort)
                            {
                                int limit = Utility.IntParse(p.Attributes["limit"], 1);

                                var size = sb.Length;
                                for (var i = 0; i < limit; i++)
                                {
                                    var bindPort = port + i;
                                    if (_host.ContainsKey(bindPort) == false)
                                    {
                                        if (host.ContainsKey(bindPort) == false)
                                        {
                                            try
                                            {
                                                host[bindPort] = BindSocket(bindPort, Proxy);
                                            }
                                            catch
                                            {
                                                sb.Append(bindPort);
                                                sb.Append(" ");

                                            }
                                        }

                                    }
                                }
                                if (sb.Length != size)
                                {
                                    sb.Append("端口已存在");
                                }
                                if (limit == 1)
                                {
                                    _urls.Add($"proxy://*:{port}");
                                }
                                else
                                {

                                    _urls.Add($"proxy://*:{port}-{limit + port - 1}");
                                }

                            }
                        }
                        break;
                    case "http":
                        // default:
                        {
                            int port = Utility.IntParse(p.Attributes["port"], 80);

                            if (_host.ContainsKey(port) == false)
                            {
                                if (host.ContainsKey(port) == false)
                                {

                                    try
                                    {
                                        host[port] = BindSocket(port, Http);// list.ToArray();
                                        _urls.Add($"http://*:{port}");

                                    }
                                    catch (Exception ex)
                                    {
                                        sb.Append($"Port:{port} {ex.Message};");
                                    }
                                }
                            }
                            else
                            {

                                host[port] = _host[port];
                                _host.Remove(port);
                                _urls.Add($"http://*:{port}");
                            }


                        }
                        break;
                }
            }
            foreach (var s in this._host.Values)
            {
                foreach (var s1 in s)
                {
                    s1.Close();
                }

            }
            this._host.Clear();
            this._host = host;

            StartMsg = sb.ToString();
            return sb.ToString();

        }
        public static HttpMimeServier Current => httpMimeServier;

        public Func<UMC.ITME.WebServlet> Handler
        {
            get; private set;
        } = () => new UMC.ITME.WebServlet();

        static HttpMimeServier httpMimeServier;
        bool IsStop = false;

        ManualResetEvent mre = new ManualResetEvent(false);
        Dictionary<String, Func<String>> cmds;
        static void StopService()
        {

            // using (var pipeClient = new NamedPipeClientStream(".", "APIUMCReStart", PipeDirection.InOut))
            // {
            //     try
            //     {
            //         pipeClient.Connect(3000);
            //         var ls = new byte[0x200];
            //         pipeClient.Write(ls, 0, $"数据已经重启完毕".WriteBytes(ls, 0));
            //         var l = pipeClient.Read(ls, 0, ls.Length);
            //         pipeClient.Close();
            //     }
            //     catch //(Exception ex)
            //     {
            //     }
            // }
        }
        public static void Start(bool isSync, Dictionary<String, Func<String>> keyValues, Func<WebServlet> func = null)
        {
            httpMimeServier = new HttpMimeServier(isSync);
            httpMimeServier.cmds = keyValues;
            if (func != null)
            {
                httpMimeServier.Handler = func;
            }
            var Instance = UMC.Web.WebResource.Instance();
            if (!(Instance is UMC.ITME.WebResource))
            {
                if (Instance.Provider == null)
                {
                    var _Provider = Reflection.Configuration("assembly")?["WebResource"] ?? Data.Provider.Create("WebResource", "UMC.Data.WebResource");

                    UMC.Web.WebResource.Instance(new UMC.ITME.WebResource(), _Provider);
                }
                else
                {

                    UMC.Web.WebResource.Instance(new UMC.ITME.WebResource(), Instance.Provider);
                }

            }

            Register(300, new HttpCheckDoWorker());
            Register(10, new HttpLogerDoWorker());
            Register(100, httpMimeServier);

            if (isSync)
            {
                StopService();
                httpMimeServier.LoadNetwork();

            }
            else
            {
                httpMimeServier.LoadNetwork();
            }


            var webr = UMC.Data.WebResource.Instance();
            // if (String.Equals(webr.Provider["repost"], "off") == false && String.IsNullOrEmpty(webr.Provider["appSecret"]) == false)
            // {
            //     httpMimeServier.Bridge();

            // }
            var caption = webr.Provider["caption"];
            if (String.IsNullOrEmpty(caption) == false)
            {
                UMC.ITME.WebServlet.AppConf.Put("title", caption);
            }
            Socket command;

            string socketPath = "/tmp/itme.sock";
            if (OperatingSystem.IsWindows())
            {
                int port = (Math.Abs(Utility.IntParse(Utility.MD5(socketPath.UTF8()))) % 1000) + 5000;

                command = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                command.Bind(new IPEndPoint(IPAddress.Loopback, port));
                command.Listen(512);
                SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                eventArgs.Completed += httpMimeServier.Unix;
                command.AcceptAsync(eventArgs);

            }
            else
            {
                if (File.Exists(socketPath))
                    File.Delete(socketPath);
                var endpoint = new UnixDomainSocketEndPoint(socketPath);

                command = new Socket(AddressFamily.Unix, SocketType.Stream, ProtocolType.Unspecified);
                command.Bind(endpoint);
                command.Listen(512);
                SocketAsyncEventArgs eventArgs = new SocketAsyncEventArgs();
                eventArgs.Completed += httpMimeServier.Unix;
                command.AcceptAsync(eventArgs);

            }



            while (httpMimeServier.IsStop == false)
            {

                httpMimeServier.mre.WaitOne(10000);

                try
                {
                    RelayAsyncArgs.CheckTimeOut();
                    CheckLink();
                    UMC.Net.NetProxy.Check();
                    HttpBridgeClient.Check();
                    UMC.Bridge.HttpBridgeServier.Check();
                }
                catch (Exception ex)
                {
                    UMC.Data.Utility.Error("Server", DateTime.Now, ex);

                }
                var now = Utility.TimeSpan();

                int count = DoWorkers.Count;
                while (DoWorkers.TryDequeue(out var _top))
                {
                    if (_top.Item1 < now)
                    {
                        try
                        {
                            _top.Item2.DoWork();
                        }
                        catch (Exception ex)
                        {
                            UMC.Data.Utility.Error("Server", DateTime.Now, ex);
                        }
                    }
                    else
                    {
                        DoWorkers.Enqueue(_top);
                    }

                    count--;
                    if (count <= 0)
                    {
                        break;
                    }
                }

            }
            command.Close();
            command.Dispose();
            Stop();

            try
            {
                // pipeServer.Close();
            }
            catch
            {

            }

        }
        public static void Stop()
        {
            try
            {
                httpMimeServier.IsStop = true;
                HotCache.Close();

                foreach (var s in httpMimeServier._host.Values)
                {
                    foreach (var s1 in s)
                    {
                        s1.Close();
                    }

                }
            }
            catch
            {

            }

        }
        int repostIP;
        public static string Load(ProviderConfiguration config)
        {
            return httpMimeServier.Config(config);
        }
        static ConcurrentQueue<Tuple<uint, IDoWorker>> DoWorkers = new ConcurrentQueue<Tuple<uint, IDoWorker>>();
        public static void Register(uint intervalTime, IDoWorker worker)
        {
            DoWorkers.Enqueue(Tuple.Create(Utility.TimeSpan() + intervalTime, worker));
        }
        String StartMsg;
        private HttpMimeServier(bool isSync)
        {

            sslServerAuthentication = new SslServerAuthenticationOptions()
            {
                ServerCertificateSelectionCallback = ServerCertificateSelectionCallback,
                CertificateRevocationCheckMode = X509RevocationMode.NoCheck,
                EncryptionPolicy = EncryptionPolicy.RequireEncryption,
                ClientCertificateRequired = false,
                EnabledSslProtocols = System.Security.Authentication.SslProtocols.Tls12,
                RemoteCertificateValidationCallback = (e, b, c, d) =>
                {
                    return true;
                },
            };


            HotCache.LoadFile(isSync);
            NetSubscribe.Subscribe("Servier", this);

            UMC.Net.APIProxy.Subscribes(_Server);

            var certs = Reflection.Configuration("certs");
            foreach (var cert in certs.Providers)
            {
                try
                {
                    var x509 = X509Certificate2.CreateFromPem(cert["publicKey"], cert["privateKey"]);
                    Certificater.Certificates[cert.Name] = new Certificater(cert.Name, x509);

                }
                catch
                {

                }
            }
            var dns = Reflection.Configuration("dns");
            foreach (var p in dns.Providers)
            {
                switch (p.Type)
                {
                    case "dns":
                        UMC.Net.NetProxy.DNS(p.Name, NetProxy.DNSType.DNS);
                        break;
                    case "dns6":
                        UMC.Net.NetProxy.DNS(p.Name, NetProxy.DNSType.DNS | NetProxy.DNSType.IP6);
                        break;
                    default:
                        if (IPAddress.TryParse(p.Type, out var address))
                        {
                            UMC.Net.NetProxy.DNS(p.Name, address);
                        }
                        break;
                }
            }
        }
        private void Proxy(object sender, SocketAsyncEventArgs eventArgs)
        {
            do
            {
                var client = eventArgs.AcceptSocket;
                eventArgs.AcceptSocket = null;
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        var ip = (client.RemoteEndPoint as IPEndPoint).Address;
                        if (ip.IsIPv4MappedToIPv6)
                        {
                            ip = ip.MapToIPv4();
                        }
                        var ipvalue = new byte[16];
                        if (ip.TryWriteBytes(ipvalue, out var l))
                        {
                            var reId = new StringValue(ipvalue, 0, l);
                            var firewall = DataFactory.Instance().Firewall(reId);
                            switch (firewall?.AuthType)
                            {
                                case Entities.AuthType.Deny:
                                    client.Close();
                                    client.Dispose();
                                    return;
                            }
                            HttpBridgeProxy.HttpsProxyAsync(client, repostIP, Memory<byte>.Empty);
                        }
                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));
        }
        private void Unix(object sender, SocketAsyncEventArgs eventArgs)
        {

            do
            {
                var client = eventArgs.AcceptSocket;
                eventArgs.AcceptSocket = null;
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        Unix(client);
                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));
        }
        readonly static StringValue Loopback = new StringValue(new byte[] { 127, 0, 0, 1 });
        async void Unix(Socket client)
        {
            var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(256);
            var timeOut = new CancellationTokenSource(5000);
            try
            {
                int size = await client.ReceiveAsync(new ArraySegment<byte>(buffer), timeOut.Token);
                if (size == 0)
                {
                    client.Close();
                    client.Dispose();
                    return;
                }
                switch (buffer[0])
                {
                    case 11:
                        {

                            var isBridge = false;
                            var reId = new StringValue(buffer.AsSpan(19, buffer[18]).ToArray());
                            var siteConfig = reId.IsEmpty() ? new SiteConfig(new Site { Root = String.Empty, Domain = String.Empty }) : DataFactory.Instance().SiteConfig(reId);
                            if (siteConfig == null)
                            {
                                var b = await UMC.Bridge.HttpBridge.Bridge(reId);

                                if (b != null)
                                {
                                    isBridge = true;
                                    siteConfig = new SiteConfig(new Site { Root = reId.UTF8(), Domain = String.Empty });
                                }
                                else
                                {
                                    client.Close();
                                    client.Dispose();
                                    return;

                                }
                            }
                            var writer = new CborWriter();
                            writer.WriteStartMap(null);
                            writer.WriteTextString("Name");
                            writer.WriteTextString(siteConfig.Root);
                            writer.WriteTextString("AppId");
                            if (reId.IsEmpty() || isBridge)
                            {
                                writer.WriteByteString(WebServlet.AppId.Span);
                                writer.WriteTextString("AppSecret");
                                writer.WriteByteString(WebServlet.AppSecret.Span);
                            }
                            else
                            {
                                writer.WriteByteString(siteConfig.AppId.Span);
                                writer.WriteTextString("AppSecret");
                                writer.WriteByteString(siteConfig.AppSecret.Span);
                            }
                            writer.WriteTextString("ApiSecureBodyTimeOut");
                            writer.WriteInt32(siteConfig.ApiSecureBodyTimeOut);
                            writer.WriteTextString("ApiSecureBodySize");
                            writer.WriteInt32(siteConfig.ApiSecureBodySize);
                            writer.WriteTextString("ApiSecureHeadSize");
                            writer.WriteInt32(siteConfig.ApiSecureHeadSize);
                            writer.WriteTextString("ApiSecureHeadTimeOut");
                            writer.WriteInt32(siteConfig.ApiSecureHeadTimeOut);
                            writer.WriteTextString("ApiSecureRepetitions");
                            writer.WriteInt32(siteConfig.ApiSecureRepetitions);
                            writer.WriteTextString("ApiSecureTime");
                            writer.WriteInt32(siteConfig.ApiSecureTime);
                            writer.WriteTextString("ApiSecureNetworkSpeed");
                            writer.WriteInt32(siteConfig.ApiSecureNetworkSpeed);
                            writer.WriteTextString("ApiSecureLockTimes");
                            writer.WriteInt32(siteConfig.ApiSecureLockTimes);
                            writer.WriteTextString("ApiSecureConnections");
                            writer.WriteInt32(siteConfig.ApiSecureConnections);
                            writer.WriteTextString("IsDisabledApiSecure");
                            writer.WriteBoolean(siteConfig.IsDisabledApiSecure);
                            writer.WriteTextString("IsDisabledFingerprint");
                            writer.WriteBoolean(siteConfig.IsDisabledFingerprint);


                            writer.WriteTextString("SLB");
                            writer.WriteInt32(siteConfig.Site.SLB ?? 0);

                            if (isBridge)
                            {
                                writer.WriteTextString("Domain");
                                writer.WriteStartMap(null);
                                writer.WriteTextString($"{reId}:0");
                                writer.WriteInt32(1);
                                writer.WriteEndMap();


                            }
                            else if (siteConfig.Site.SiteKey.HasValue)
                            {

                                if (siteConfig.ImagesConf.Length > 0)
                                {
                                    writer.WriteTextString("PathImage");

                                    writer.WriteStartArray(null);
                                    foreach (var m in siteConfig.ImagesConf)
                                    {
                                        writer.WriteStartMap(null);
                                        if (m.EndPath.Length > 0)
                                        {
                                            writer.WriteTextString($"{m.StartPath}*{m.EndPath}");
                                        }
                                        else
                                        {
                                            writer.WriteTextString(m.StartPath.UTF8());
                                        }

                                        writer.WriteEndMap();
                                        writer.WriteTextString("Width");
                                        writer.WriteInt32(m.Value.Width);
                                        writer.WriteTextString("Height");
                                        writer.WriteInt32(m.Value.Height);
                                        writer.WriteTextString("FontSize");
                                        writer.WriteInt32(m.Value.FontSize);
                                        writer.WriteTextString("ImageSize");
                                        writer.WriteInt32(m.Value.ImageSize);
                                        writer.WriteTextString("Padding");
                                        writer.WriteInt32(m.Value.Padding);
                                        writer.WriteTextString("Postion");
                                        writer.WriteInt32(m.Value.Postion);
                                        writer.WriteTextString("Model");
                                        writer.WriteInt32(m.Value.Model);

                                        if (String.IsNullOrEmpty(m.Value.FontColor) == false)
                                        {
                                            writer.WriteTextString("FontColor");
                                            writer.WriteTextString(m.Value.FontColor);
                                        }

                                        if (String.IsNullOrEmpty(m.Value.Font) == false)
                                        {
                                            writer.WriteTextString("Font");
                                            writer.WriteTextString(m.Value.Font);
                                        }
                                        if (String.IsNullOrEmpty(m.Value.Format) == false)
                                        {
                                            writer.WriteTextString("Format");
                                            writer.WriteTextString(m.Value.Format);
                                        }
                                        if (String.IsNullOrEmpty(m.Value.WateRmarkText) == false)
                                        {
                                            writer.WriteTextString("WateRmarkText");
                                            writer.WriteTextString(m.Value.WateRmarkText);
                                        }
                                        if (String.IsNullOrEmpty(m.Value.WateRmark) == false)
                                        {
                                            writer.WriteTextString("WateRmark");
                                            writer.WriteTextString(m.Value.WateRmark);
                                        }

                                        writer.WriteEndMap();

                                        writer.WriteEndMap();

                                    }
                                    writer.WriteEndArray();

                                }

                                var pkey = siteConfig.Site.SiteKey.Value.StringValue();
                                var ms = HotCache.Find(new ProxySite()).Where(r => r.ConfigKey.Contains(pkey.Span));
                                if (ms.Count() > 0)
                                {
                                    writer.WriteTextString("ProxySite");
                                    writer.WriteStartMap(null);
                                    foreach (var m in ms)
                                    {
                                        writer.WriteByteString(m.Domain.Span);
                                        if (m.Type.Int32() == 1 && m.ProxyIP.IsEmpty() == false)
                                        {
                                            buffer[0] = 0x01;
                                            m.ProxyIP.Span.CopyTo(buffer.AsSpan(1));
                                            writer.WriteByteString(buffer.AsSpan(0, 1 + m.ProxyIP.Length));
                                        }
                                        else
                                        {
                                            writer.WriteByteString((m.ProxyIP ?? StringValue.Empty).Span);

                                        }
                                    }

                                    writer.WriteEndMap();

                                }
                            }
                            else
                            {

                            }


                            var hosts = HotCache.Find(new SiteHost { Root = reId }, false, 0, 500, out var _);


                            writer.WriteTextString("Sites");

                            writer.WriteStartArray(null);
                            foreach (var host in hosts)
                            {
                                if (reId.IsEmpty())
                                {
                                    if (host.IsAuthModel == true)
                                    {
                                        writer.WriteTextString(host.Host.UTF8());

                                    }
                                    else
                                    {
                                        writer.WriteByteString(host.Host.Span);
                                    }

                                }
                                else
                                {
                                    writer.WriteByteString(host.Host.Span);

                                }
                            }

                            if (reId.IsEmpty())
                            {
                                var provider = Data.WebResource.Instance().Provider;
                                var authDomain = provider["auth"];
                                if (String.IsNullOrEmpty(authDomain) == false)
                                {
                                    var host = String.Format("{0}{1}{2}", authDomain, provider["union"] ?? ".", provider["domain"]).UTF8();
                                    if (hosts.FirstOrDefault(r => r.Host.Span.SequenceEqual(host)) == null)
                                    {
                                        writer.WriteByteString(host);
                                    }
                                }
                            }
                            writer.WriteEndArray();



                            writer.WriteTextString("HighFrequency");

                            writer.WriteStartArray(null);

                            var HighFrequency = (reId.IsEmpty() ? WebServlet.HighFrequency : siteConfig.HighFrequency).Span.ToArray();//.Span;// WebServlet.HighFrequency;

                            foreach (var h in HighFrequency)
                            {
                                writer.WriteByteString(h.StartPath.Span);
                                writer.WriteByteString(h.EndPath.Span);
                            }
                            foreach (var v in siteConfig.StatusPage)
                            {
                                if (v.Value == 0)
                                {
                                    writer.WriteByteString(v.StartPath.Span);
                                    writer.WriteByteString(v.EndPath.Span);
                                }
                            }
                            foreach (var v in HttpProxy.StaticPage.Split((byte)','))
                            {
                                writer.WriteByteString(StringValue.Empty.Span);
                                writer.WriteByteString(v.Span);

                            }

                            writer.WriteEndArray();

                            if (siteConfig.AllowAllPath && siteConfig.IsFile == false)
                            {
                                var subSite = siteConfig.SubSite;
                                if (subSite.Length > 0)
                                {
                                    writer.WriteTextString("SubSite");

                                    writer.WriteStartMap(null);
                                    foreach (var sub in subSite)
                                    {
                                        writer.WriteTextString(sub.Key.UTF8());
                                        writer.WriteTextString(sub.Value);
                                    }
                                    writer.WriteEndMap();
                                }

                                if (siteConfig.Domains.Length > 0)
                                {
                                    var mainUrl = new Uri(siteConfig.Domains[0]);
                                    if (mainUrl.Scheme == "https")
                                    {
                                        writer.WriteTextString("SNI");//,mainUrl.Host);
                                        writer.WriteTextString(mainUrl.Host);
                                    }
                                    writer.WriteTextString("Domain");

                                    writer.WriteStartMap(null);
                                    writer.WriteTextString($"{mainUrl.Host}:{mainUrl.Port}");
                                    writer.WriteInt32(siteConfig.Weights[0]);

                                    for (int i = 1; i < siteConfig.Domains.Length; i++)// (var v in siteConfig.Domains)
                                    {
                                        var uri = new Uri(siteConfig.Domains[i]);

                                        writer.WriteTextString($"{uri.Host}:{uri.Port}");

                                        writer.WriteInt32(siteConfig.Weights[i]);

                                    }
                                    writer.WriteEndMap();
                                }

                            }

                            writer.WriteEndMap();
                            await client.SendAsync(writer.Encode(), SocketFlags.None);

                            client.Close();
                            client.Dispose();
                            return;
                        }
                    case 10:
                        {
                            // if (size > 1)
                            // {
                            //     int len = buffer[1];
                            //     var clientIp = new StringValue(buffer.AsSpan(2, len).ToArray());

                            //     var domain = new StringValue(buffer, len + 1, buffer[len] - 2);
                            //     len += 1;
                            //     len += domain.Length;
                            //     ushort port = (ushort)(buffer[len] << 8 | buffer[len + 1]);
                            //     await client.SendAsync(Socks5Server.Check(clientIp, domain, port));

                            //     client.Close();
                            //     client.Dispose();
                            //     return;
                            // }
                            var writer = new CborWriter();
                            writer.WriteStartArray(null);

                            writer.WriteInt32(Utility.IntParse(WebServlet.AppId.Span));

                            writer.WriteByteString(ITME.WebServlet.MainDomainValue.Span);

                            writer.WriteTextString(ITME.WebServlet.DomainUnion.ToString());

                            writer.WriteStartMap(null);
                            writer.WriteTextString("AppId");
                            writer.WriteByteString(WebServlet.AppId.Span);
                            writer.WriteTextString("AppCode");
                            writer.WriteTextString(Utility.Parse36Encode(Utility.IntParse(WebServlet.AppId.Span)));
                            writer.WriteTextString("AppSecret");
                            writer.WriteByteString(WebServlet.AppSecret.Span);
                            var ms = HotCache.Find(new ProxySite());
                            if (ms.Length > 0)
                            {
                                writer.WriteTextString("ProxySite");
                                writer.WriteStartMap(null);
                                foreach (var m in ms)
                                {
                                    writer.WriteByteString(m.Domain.Span);
                                    if (m.Type.Int32() == 1 && m.ProxyIP.IsEmpty() == false)
                                    {
                                        buffer[0] = 0x01;
                                        m.ProxyIP.Span.CopyTo(buffer.AsSpan(1));
                                        writer.WriteByteString(buffer.AsSpan(0, 1 + m.ProxyIP.Length));
                                    }
                                    else
                                    {
                                        writer.WriteByteString((m.ProxyIP ?? StringValue.Empty).Span);

                                    }
                                }

                                writer.WriteEndMap();

                            }
                            writer.WriteEndMap();

                            var hosts = HotCache.Find(new Firewall { }, false, 0, 500, out var _);

                            writer.WriteStartArray(null);

                            var b = new byte[17];
                            foreach (var host in hosts)
                            {
                                b[0] = (byte)(host.AuthType ?? AuthType.Check);
                                if (b[0] > 0)
                                {
                                    host.Fingerprint.Span.CopyTo(b.AsSpan(1));
                                    writer.WriteByteString(b.AsSpan(0, host.Fingerprint.Length + 1));
                                }
                            }
                            writer.WriteEndArray();


                            writer.WriteEndArray();
                            await client.SendAsync(writer.Encode(), SocketFlags.None);

                            var certs = HotCache.Find(new SiteCert { }, false, 0, 500, out var nextIndex)
                           .Where(r => r.PrivateKey.IsEmpty() == false && r.PublicKey.IsEmpty() == false).ToArray();

                            int time = 0;

                            size = await client.ReceiveAsync(new ArraySegment<byte>(buffer), timeOut.Token);
                            if (size > 0)
                            {
                                writer.Reset();
                                writer.WriteStartArray(2);
                                writer.WriteByteString(CertKey.UTF8());
                                writer.WriteByteString(PrivateKey.UTF8());
                                writer.WriteEndArray();
                                await client.SendAsync(writer.Encode(), SocketFlags.None);
                                while (time < certs.Count())
                                {
                                    size = await client.ReceiveAsync(new ArraySegment<byte>(buffer), timeOut.Token);
                                    if (size > 0)
                                    {
                                        var cert = certs[time];
                                        writer.Reset();
                                        writer.WriteStartArray(3);
                                        writer.WriteByteString(cert.Domain.Span);
                                        writer.WriteByteString(cert.PublicKey.Span);
                                        writer.WriteByteString(cert.PrivateKey.Span);
                                        writer.WriteEndArray();

                                        await client.SendAsync(writer.Encode(), SocketFlags.None);
                                        time++;
                                    }
                                    else
                                    {
                                        break;
                                    }

                                }
                            }
                            client.Close();
                            client.Dispose();
                        }
                        return;
                    case (byte)'G':
                    case (byte)'H':
                    case (byte)'P':
                    case (byte)'D':
                    case (byte)'T':
                        new HttpMimeSocket(client, Loopback, buffer.AsMemory(0, size), false);
                        return;
                    case 13:
                        Command(client, buffer.AsMemory(1, size - 1));
                        return; ;
                }
            }
            catch// (Exception ex)
            {
                client.Close();
                client.Dispose();
            }
            finally
            {
                timeOut.Dispose();
                System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
            }
        }

        private void Http(object sender, SocketAsyncEventArgs eventArgs)
        {
            do
            {
                // UnixDomainSocketEndPoint
                var client = eventArgs.AcceptSocket;
                eventArgs.AcceptSocket = null;
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        var ip = (client.RemoteEndPoint as IPEndPoint).Address;
                        if (ip.IsIPv4MappedToIPv6)
                        {
                            ip = ip.MapToIPv4();
                        }
                        var ipvalue = new byte[16];
                        if (ip.TryWriteBytes(ipvalue, out var l))
                        {
                            var reId = new StringValue(ipvalue, 0, l);
                            var firewall = DataFactory.Instance().Firewall(reId);
                            switch (firewall?.AuthType)
                            {
                                case Entities.AuthType.Deny:
                                    client.Close();
                                    client.Dispose();
                                    return;
                            }
                            new HttpMimeSocket(client, reId);
                        }
                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));


        }
        async void Https(Socket client, StringValue reId, bool IsSecure)
        {
            var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(256);
            var timeOut = new CancellationTokenSource(5000);

            try
            {
                int size = await client.ReceiveAsync(new ArraySegment<byte>(buffer), timeOut.Token);
                if (size == 0)
                {
                    client.Close();
                    client.Dispose();
                    return;
                }
                StringValue proxyPort = StringValue.Empty;
                switch (buffer[0])
                {

                    case 0x06:
                        int len = buffer[1];
                        reId = new StringValue(buffer.AsSpan(2, len).ToArray());
                        len += 2;
                        var firewall = DataFactory.Instance().Firewall(reId);
                        switch (firewall?.AuthType)
                        {
                            case Entities.AuthType.Allow:
                                IsSecure = true;
                                break;
                            case Entities.AuthType.Deny:
                                client.Close();
                                client.Dispose();
                                return;
                        }
                        if (buffer[len] == 0x00)
                        {
                            Array.Copy(buffer, 1 + len, buffer, 0, size - len - 1);
                            size -= len + 1;

                        }
                        else
                        {
                            var domain = new StringValue(buffer, len + 1, buffer[len] - 2);
                            len += 1;
                            len += domain.Length;
                            ushort port = (ushort)(buffer[len] << 8 | buffer[len + 1]);
                            await client.SendAsync(HttpBridgeProxy.HttpsProxyAsync(reId, domain, port));
                            client.Close();
                            client.Dispose();
                            return;
                        }
                        break;
                    case 0x05:
                        Socks5Server.HandleClientAsync(client, buffer.AsMemory(0, size));
                        return;
                    case 67:
                        HttpBridgeProxy.HttpsProxyAsync(client, repostIP, buffer.AsMemory(0, size));
                        return;
                    case 0x02:
                        await UMC.Bridge.HttpBridge.Bridge(client, buffer.AsMemory(0, size));
                        return;
                    case 0x03:
                        var size2 = buffer[1] + 2;
                        if (size2 <= size)
                        {
                            proxyPort = new StringValue(buffer.AsSpan(2, size2 - 2).ToArray());
                        }
                        else
                        {
                            client.Close();
                            client.Dispose();
                            return;
                        }
                        Array.Copy(buffer, size2, buffer, 0, size - size2);
                        size = size - size2;
                        if (size < 5)
                        {
                            size += await client.ReceiveAsync(new ArraySegment<byte>(buffer, size, buffer.Length - size), timeOut.Token);
                        }

                        break;
                    case 0x04:
                        int index = buffer[1] + 2;
                        int configKey = 0;
                        if (index == 6)
                        {
                            configKey = System.Buffers.Binary.BinaryPrimitives.ReadInt32BigEndian(buffer.AsSpan(2));
                        }
                        int count = (buffer[index] << 8) | buffer[index + 1];

                        var buffer3 = System.Buffers.ArrayPool<byte>.Shared.Rent(count);

                        size -= index + 2;
                        Array.Copy(buffer, index + 2, buffer3, 0, size);

                        System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
                        buffer = buffer3;


                        while (size < count)
                        {
                            int len2 = await client.ReceiveAsync(new ArraySegment<byte>(buffer, size, buffer.Length - size), timeOut.Token);
                            if (len2 == 0)
                            {
                                client.Close();
                                client.Dispose();
                                return;
                            }
                            else
                            {
                                size += len2;
                            }
                        }
                        var header = buffer.AsMemory(0, size);
                        Socks5Server.OR(header.Span, 0x04);

                        if (HttpsStream.TryGetFrameHeader(header.Span, out var tlsSite2) == false)
                        {
                            tlsSite2.IsSecure = IsSecure;
                            await HttpBridgeProxy.HttpsProxyAsync(client, tlsSite2, configKey, header);

                        }
                        else
                        {

                            client.Close();
                            client.Dispose();
                        }
                        return;

                }
                switch (buffer[0])
                {

                    case (byte)'G':
                    case (byte)'H':
                    case (byte)'P':
                    case (byte)'D':
                    case (byte)'T':
                        new HttpMimeSocket(client, reId, buffer.AsMemory(0, size), true);
                        return;
                    case 22:
                        break;
                    default:
                        client.Close();
                        client.Dispose();
                        return;
                }

                int length = ((buffer[3] << 8) | buffer[4]) + HttpsStream.TlsFrameHelper.HeaderSize;

                var buffer2 = System.Buffers.ArrayPool<byte>.Shared.Rent(length);
                Array.Copy(buffer, 0, buffer2, 0, size);
                System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
                buffer = buffer2;


                while (size < length)
                {
                    int len = await client.ReceiveAsync(new ArraySegment<byte>(buffer, size, buffer.Length - size), timeOut.Token);
                    if (len == 0)
                    {
                        client.Close();
                        client.Dispose();
                        return;
                    }
                    else
                    {
                        size += len;
                    }
                }
                if (HttpsStream.TryGetFrameHeader(buffer.AsSpan(0, size), out var tlsSite) == false)
                {
                    tlsSite.IsSecure = IsSecure;
                    await HttpBridgeProxy.HttpsProxyAsync(client, tlsSite, 0, buffer.AsMemory(0, size));
                    return;
                }
                else
                {
                    tlsSite.IsSecure = IsSecure;
                    tlsSite.ProxyCode = proxyPort;
                }

                SslStream sslStream = new SslStream(new HttpsStream(client, buffer.AsMemory(0, size)));

                await sslStream.AuthenticateAsServerAsync(sslServerAuthentication, timeOut.Token);

                if (tlsSite.IsHome == false && tlsSite.Site == null && tlsSite.SiteHost == null)
                {
                    UMC.Bridge.HttpBridge.Bridge(tlsSite, sslStream, client, reId);
                }
                else
                {

                    var fire = DataFactory.Instance().Firewall(tlsSite.Finger);

                    switch (fire?.AuthType)
                    {
                        case Entities.AuthType.Allow:
                            {
                                new HttpsMimeSocket(sslStream, client, tlsSite, reId) { IsPass = true };
                            }
                            break;
                        case Entities.AuthType.Deny:
                            HttpsMimeSocket.Challenge(tlsSite.Host, 423, true, "Deny", reId, "en-US.js", tlsSite.Fingerprint, tlsSite.Site?.Root ?? String.Empty, sslStream.Write);
                            sslStream.Close();
                            sslStream.Dispose();
                            client.Close();
                            client.Dispose();
                            break;
                        default:
                            {
                                new HttpsMimeSocket(sslStream, client, tlsSite, reId);
                            }
                            break;
                    }
                }
            }
            catch// (Exception ex)
            {
                client.Close();
                client.Dispose();
            }
            finally
            {
                timeOut.Dispose();
                System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
            }




        }
        void Https(Socket client)
        {
            var ipvalue = new byte[16];
            var IsSecure = false;

            var ip = (client.RemoteEndPoint as IPEndPoint).Address;
            if (ip.IsIPv4MappedToIPv6)
            {
                ip = ip.MapToIPv4();
            }
            if (ip.TryWriteBytes(ipvalue, out var l))
            {
                var reId = new StringValue(ipvalue, 0, l);
                if (IPAddress.IsLoopback(ip) == false)
                {
                    var firewall = DataFactory.Instance().Firewall(reId);
                    switch (firewall?.AuthType)
                    {
                        case Entities.AuthType.Allow:
                            IsSecure = true;
                            break;
                        case Entities.AuthType.Deny:
                            client.Close();
                            client.Dispose();
                            return;
                    }
                }

                Https(client, reId, IsSecure);
            }
        }
        void Command(Socket socket, Memory<byte> header)
        {
            using (var pipeServer = new NetworkStream(socket, true))
            {
                try
                {

                    var str = header.Span.UTF8().Split(' ');
                    switch (str[0])
                    {
                        case "socks":
                            if (str.Length > 2)
                            {
                                if (IPAddress.TryParse(str[1], out var ip))
                                {
                                    var buffer = System.Buffers.ArrayPool<byte>.Shared.Rent(0x200);
                                    var userName = new StringValue(str[2]);
                                    var clientIP = new StringValue(ip.GetAddressBytes());
                                    userName.Span.CopyTo(buffer);
                                    clientIP.Span.CopyTo(buffer.AsSpan(userName.Length));

                                    WebServlet.AppSecret.Span.CopyTo(buffer.AsSpan(userName.Length + clientIP.Length));
                                    var size = userName.Length + clientIP.Length + 16;

                                    Utility.MD5(buffer.AsSpan(0, size), buffer.AsSpan(size));

                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"单机加密码: {Utility.ToBase64String(buffer.AsSpan(size, 16))}\r\n"));
                                    System.Buffers.ArrayPool<byte>.Shared.Return(buffer);
                                }
                                else
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}不是正确的IP\r\n"));
                                }
                            }
                            else
                            {
                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"格式不正确\r\n"));
                            }
                            break;
                        case "reset":
                            {
                                if (str.Length > 1)
                                {
                                    var user = Data.DataFactory.Instance().User(str[1]);
                                    if (user != null)
                                    {
                                        UMC.Security.Membership.Instance().AddFlags(user.Username, Security.UserFlags.Reset);
                                        UMC.Security.Membership.Instance().Password(user.Username, "apiumc");
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}密码已经重置为apiumc。\r\n"));

                                    }
                                    else
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"不存在{str[1]}账户\r\n"));
                                    }
                                }
                                else
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"正在使用快速重启ITME\r\n"));
                                    httpMimeServier.IsStop = true;
                                    httpMimeServier.mre.Set();
                                }
                            }
                            break;
                        case "domain":
                            if (str.Length > 1)
                            {
                                var Domain = str[1];// Config["domain"];

                                if (Regex.IsMatch(Domain, @"^(?:[a-z0-9](?:[a-z0-9-]{0,61}[a-z0-9])?\.)+[a-z0-9][a-z0-9-]{0,61}[a-z0-9]$", RegexOptions.IgnoreCase) == false)
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}非有效的域名\r\n"));
                                }
                                else
                                {
                                    var domainValue = new StringValue(Domain);
                                    if (DataFactory.Instance().Host(domainValue) != null)
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}此域名已经被引用\r\n"));
                                    }
                                    else
                                    {
                                        var h = new SiteHost { Host = domainValue, Root = StringValue.Empty, IsAuthModel = true };
                                        DataFactory.Instance().Put(h);
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}添加辅助域名成功\r\n"));

                                    }
                                }
                            }
                            else
                            {
                                var asshosts = HotCache.Find(new SiteHost { Root = StringValue.Empty });
                                if (asshosts.Length > 0)
                                {
                                    foreach (var ass in asshosts)
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{ass.Host} {ass.IsAuthModel}\r\n"));
                                    }
                                }
                                else
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"未有辅助域名\r\n"));

                                }
                            }
                            break;
                        case "clear":
                            if (str.Length > 1)
                            {

                                var user = Data.DataFactory.Instance().User(str[1]);
                                var flags = user?.Flags ?? UMC.Security.UserFlags.Normal;
                                if ((flags & Security.UserFlags.Lock) == Security.UserFlags.Lock)
                                {
                                    flags ^= Security.UserFlags.Lock;

                                    Data.DataFactory.Instance().Put(new Data.Entities.User
                                    {
                                        Flags = flags,
                                        Username = user.Username,
                                        IsDisabled = false,
                                        ExpireTime = 0,
                                        Id = user.Id
                                    });
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}已解除锁定。\r\n"));
                                }
                                else
                                {

                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}未被锁定。\r\n"));
                                }
                            }
                            else
                            {
                                UMC.Data.Reflection.Instance().ClearCache();
                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("配置缓存已经清空。\r\n"));
                            }
                            break;
                        case "biome":
                            if (str.Length > 1)
                            {
                                var user = Data.DataFactory.Instance().User(str[1]);
                                if (String.IsNullOrEmpty(user?.Biometric))
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}生物特性未登记\r\n"));
                                }
                                else
                                {
                                    var identity = UMC.Security.Membership.Instance().Identity(user.Id.Value);
                                    if (identity?.IsInRole(UMC.Security.Membership.AdminRole) == true)
                                    {
                                        UMC.Security.Membership.Instance().AddFlags(user.Username, Security.UserFlags.Biometric);
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}生物特性已开通\r\n"));

                                    }
                                    else
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"指令只支持开启管理员生物特性认证\r\n"));

                                    }
                                }
                            }
                            else
                            {
                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("biome指令需要带参数\r\n"));
                            }
                            break;

                        case "repost":
                            // if (str.Length > 1)
                            // {
                            //     switch (str[1])
                            //     {
                            //         case "start":
                            //             // pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(2)));
                            //             break;
                            //         case "stop":
                            //             // pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(1)));
                            //             break;
                            //         default:
                            //             // pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"repost {str[1]}指令 不能识别。\r\n"));
                            //             break;
                            //     }
                            // }
                            // else
                            // {
                            //     // pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(HttpBridgeClient.ServerChange(0)));
                            // }
                            break;
                        case "https":
                            {

                                var hosts = Reflection.Configuration("host");
                                if (str.Length > 1)
                                {

                                    if (Utility.IntParse(str[1], 0) > 0)
                                    {
                                        var http = UMC.Data.Provider.Create("ssl", "https");
                                        http.Attributes["port"] = str[1];

                                        hosts.Add(http);

                                        Reflection.Configuration("host", hosts);

                                    }

                                }
                                else
                                {
                                    if (hosts.ContainsKey("ssl") == false)
                                    {
                                        var http = UMC.Data.Provider.Create("ssl", "https");

                                        http.Attributes["port"] = "443";

                                        hosts.Add(http);

                                        Reflection.Configuration("host", hosts);

                                    }
                                }
                                httpMimeServier.Config(Reflection.Configuration("host"));
                            }
                            goto case "info";
                        case "ssl":
                            {
                                if (str.Length > 1)
                                {
                                    var host = str[1];

                                    if (System.Text.RegularExpressions.Regex.IsMatch(host, @"^([a-z0-9\*]([a-z0-9\-]{0,61}[a-z0-9])?\.)+[a-z0-9]{1,6}$") == false)
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"域名格式不正确。\r\n"));
                                        break;
                                    }

                                    var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
                                    if (String.IsNullOrEmpty(secret))
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("\a主体未登记，请在云桌面中完成登记\r\n"));
                                        break;
                                    }
                                    var webr2 = new Uri(APIProxy.Uri, "Certificater").WebRequest();
                                    UMC.ITME.Utility.Sign(webr2, secret);

                                    var jsonStr = webr2.Post(new WebMeta().Put("type", "apply", "domain", host).Put("dcv", str.Length > 2 ? str[2] : null), out var webr);


                                    if (webr.StatusCode == System.Net.HttpStatusCode.OK)
                                    {
                                        var hs = JSON.Deserialize<WebMeta>(jsonStr);
                                        if (string.Equals(hs["code"], "success"))
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(hs["msg"] ?? "\t\b正在签发证书,大约一分钟签发完成\r\n"));

                                        }
                                        else if (string.Equals(hs["code"], "completed"))
                                        {
                                            if (Certificater.Certificates.TryGetValue(host, out var _cert) == false || _cert.Certificate == null)
                                            {
                                                webr2.Post(new WebMeta().Put("type", "cert", "domain", host), UMC.ITME.Utility.Certificate);
                                            }
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(String.Format("{0}\r\n\r\n强烈建议：请在\b云桌面->应用设置->网关服务\f中管理证书\r\n", hs["msg"])));

                                        }
                                        else
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(String.Format("{0}\r\n\r\n强烈建议：请在\b云桌面->应用设置->网关服务\f中管理证书\r\n", hs["msg"])));

                                        }

                                    }
                                    else
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(jsonStr ?? $"请确保域名“{host}”解释到服务器，并开放80端口\r\n"));
                                    }

                                }
                                else
                                {

                                    var now = UMC.Data.Utility.TimeSpan();
                                    var ls = Certificater.Certificates.Values.OrderBy(r => r.Time);
                                    var sb = new StringBuilder();
                                    sb.AppendLine("  过期\t\t\t\t证书");
                                    foreach (var r in ls)
                                    {
                                        sb.AppendLine($"{UMC.ITME.Utility.Expire(now, r.Time, "\a正在签发")}\t\t\t{r.Name}");
                                    }
                                    if (ls.Count() == 0)
                                    {
                                        sb.AppendLine("\t\t还未有证书");
                                    }
                                    else
                                    {
                                        sb.AppendLine();
                                        sb.AppendLine("强烈建议：请在\b云桌面->应用设置->网关服务\f中管理证书");
                                    }
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
                                }

                            }
                            break;
                        case "check":
                            if (str.Length > 1)
                            {
                                var key = UMC.Data.Utility.Parse36Encode(UMC.Data.Utility.IntParse(new Guid(UMC.Data.Utility.MD5(System.AppContext.BaseDirectory)))); ;

                                if (String.Equals(key, str[1]) == false)
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(UMC.Data.Utility.MapPath("~")));
                                }
                            }
                            break;
                        case "dns":
                            switch (str.Length)
                            {
                                case 1:
                                    var em2 = UMC.Net.NetProxy.DNS().GetEnumerator();
                                    while (em2.MoveNext())
                                    {
                                        if (em2.Current.Value.Item3.Length > 0)
                                        {
                                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{em2.Current.Key}:{em2.Current.Value.Item3[0]}\r\n"));
                                        }
                                    }
                                    break;
                                case 2:
                                    var adds = UMC.Net.NetProxy.DNSToIPAsync(str[1]).Result.Select(a => a.ToString()).ToArray();
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]} :{String.Join(",", adds)}\r\n"));
                                    break;
                                case 3:
                                    if (IPAddress.TryParse(str[2], out var address))
                                    {
                                        UMC.Net.NetProxy.DNS(str[1], address);

                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[1]}临时解释设置成功\r\n"));
                                    }
                                    else
                                    {
                                        pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"{str[2]}不是有效的IP地址\r\n"));//：{UMC.Data.Utility.MapPath("~")}"));
                                    }
                                    break;
                            }
                            if (str.Length > 1)
                            {
                                Utility.SaveDNS();
                            }
                            break;
                        case "http":
                        case "start":
                            if (str.Length > 1)
                            {
                                if (Utility.IntParse(str[1], 0) > 0)
                                {
                                    var http = UMC.Data.Provider.Create("*", "http");
                                    http.Attributes["port"] = str[1];

                                    var hosts = Reflection.Configuration("host");
                                    hosts.Add(http);

                                    Reflection.Configuration("host", hosts);

                                }
                            }
                            httpMimeServier.Config(Reflection.Configuration("host"));
                            goto case "info"; ;
                        case "Stop":
                            // Console.Error.Write("stop");
                            Stop();
                            httpMimeServier.mre.Set();
                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("正在转移端口控制权。\r\n"));
                            break;
                        case "stop":
                            Stop();
                            httpMimeServier.mre.Set();
                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes("正在停止ITME服务。\r\n"));
                            return;
                        case "info":
                            {

                                var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];
                                var sb = new StringBuilder();

                                if (String.IsNullOrEmpty(httpMimeServier.StartMsg) == false)
                                {
                                    sb.AppendLine(httpMimeServier.StartMsg);
                                    httpMimeServier.StartMsg = String.Empty;
                                }
                                if (httpMimeServier._urls.Count > 0)
                                {
                                    sb.Append("监听地址：\b");
                                    sb.AppendJoin("\f, \b", httpMimeServier._urls);
                                    sb.AppendLine();

                                    if (String.IsNullOrEmpty(secret))
                                    {
                                        sb.AppendLine($"转发服务：\a主体未登记\f，登记后，才可开启");
                                    }
                                    else// if (HttpBridgeClient.IsRunning)
                                    {
                                        var bridge = UMC.Data.WebResource.Instance().Provider["bridge"];
                                        if (String.IsNullOrEmpty(bridge) == false)
                                            sb.AppendLine($"转发网址：\b{bridge}");
                                        // }
                                        // else if (httpMimeServier.isBridging)
                                        // {
                                        //     var bridge = UMC.Data.WebResource.Instance().Provider["bridge"];
                                        //     sb.AppendLine($"转发网址：{bridge}  \a[连接中]");
                                        // }
                                        // else
                                        // {
                                        //     sb.AppendLine($"转发服务：请用[repost start]指令来开启转发服务");
                                    }
                                }
                                else
                                {
                                    sb.AppendLine("监听地址：\a监听失败");
                                }
                                sb.AppendLine();

                                var provider = UMC.Data.WebResource.Instance().Provider;
                                var caption = provider.Attributes["caption"];

                                if (String.IsNullOrEmpty(secret) == false)
                                {
                                    var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest();
                                    UMC.ITME.Utility.Sign(webr, secret);
                                    var result = webr.Get(out var xhr);
                                    if (xhr?.StatusCode == HttpStatusCode.OK)
                                    {
                                        var meta = JSON.Deserialize<WebMeta>(result) ?? new WebMeta();

                                        if (String.Equals(meta["caption"], caption) == false)
                                        {
                                            caption = meta["caption"];
                                            provider.Attributes["caption"] = caption;
                                            var pc = Reflection.Configuration("assembly") ?? new ProviderConfiguration();
                                            pc.Add(provider);
                                            Reflection.Configuration("assembly", pc);

                                        }
                                        if (meta.ContainsKey("sign") && meta.ContainsKey("signKey"))
                                        {
                                            License.Put(meta["signKey"].Split(","), meta["sign"]);
                                        }

                                        if (System.Net.IPAddress.TryParse(meta.Get("dns"), out var ipAddr))
                                        {
                                            DnsServer.IterativeDNS = new System.Net.IPEndPoint(ipAddr, 53);
                                        }


                                    }
                                    if (String.IsNullOrEmpty(caption) == false)
                                    {
                                        sb.AppendLine($"注册主体：\b{caption} ");
                                        UMC.ITME.WebServlet.AppConf.Put("title", caption);
                                    }
                                    var lic = License.GetLicense("UserSession", 1000);
                                    if (lic.Quantity > 0)
                                    {
                                        sb.AppendLine($"版权信息：\r{lic.Quantity}\f个会话规模使用授权");
                                    }
                                    else
                                    {
                                        sb.AppendLine($"版权信息：\b不限\f会话规模使用授权");
                                    }
                                    if (lic.ExpireTime > 0)
                                    {
                                        var sttr = "已过期";
                                        sb.AppendLine($"版权时效：\r{Utility.Expire(Utility.TimeSpan(), lic.ExpireTime, sttr)}");

                                    }

                                    Data.Caches.ICacheSet cacheSet = UMC.Data.HotCache.Cache<UMC.Data.Entities.Session>();
                                    if ((cacheSet.Count > lic.Quantity && lic.Quantity > 0) || (lic.ExpireTime > 0 && lic.ExpireTime < Utility.TimeSpan()))
                                    {
                                        sb.AppendLine();
                                        sb.AppendLine($"版权合规：当前会话规模\r已超\f限制，将会影响您的正常使用。");
                                    }
                                }
                                else
                                {
                                    sb.AppendLine($"注册主体：\a主体未登记\f，请在云桌面->应用设置->安全注册中完成登记");

                                }


                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(sb.ToString()));
                            }
                            break;
                        case "pool":
                            pipeServer.Write(System.Text.Encoding.UTF8.GetBytes(Pool()));
                            break;

                        default:
                            if (httpMimeServier?.cmds?.ContainsKey(str[0]) == true)
                            {
                                var v = httpMimeServier?.cmds?[str[0]]?.Invoke();
                                if (String.IsNullOrEmpty(v))
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"已执行\b{str[0]}\f关联配置\r\n"));

                                }
                                else
                                {
                                    pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"已执行\b{str[0]}\f关联配置\r\n执行结果为:\a{v}\f\r\n"));
                                }
                            }
                            else
                            {

                                pipeServer.Write(System.Text.Encoding.UTF8.GetBytes($"不能识别指令\r{str[0]}\f\r\n"));
                            }
                            break;
                    }
                }
                catch //(SocketException)
                {
                    // break;
                }
                finally
                {
                    // byteChunk.Dispose();
                    // System.Buffers.ArrayPool<byte>.Shared.Return(bufer);
                    // pipeServer.Disconnect();
                }

            }

            // pipeServer.Close();


        }
        private void Https(object sender, SocketAsyncEventArgs eventArgs)
        {
            do
            {
                var client = eventArgs.AcceptSocket;
                eventArgs.AcceptSocket = null;
                switch (eventArgs.SocketError)
                {
                    case SocketError.OperationAborted:
                        return;
                    case SocketError.Success:
                        Https(client);

                        break;
                }
            } while (!Accept((Socket)sender, eventArgs));


        }
        public static bool Accept(Socket socket, SocketAsyncEventArgs eventArgs)
        {
            try
            {
                return socket.AcceptAsync(eventArgs);
            }
            catch
            {
                return true;
            }
        }
        bool isBridging = false;
        void Bridge()
        {
            isBridging = true;

            var secret = UMC.Data.WebResource.Instance().Provider["appSecret"];

            var webr = new Uri(APIProxy.Uri, "Transfer").WebRequest();

            UMC.ITME.Utility.Sign(webr, secret);
            webr.Get(webr =>
            {
                webr.ReadAsString(json =>
                {
                    isBridging = false;
                    var meta = JSON.Deserialize<WebMeta>(json);
                    if (meta.ContainsKey("bridge"))
                    {
                        var domain = meta["domain"];
                        var bridgeUrl = meta["bridge"];

                        var provider = Data.WebResource.Instance().Provider;
                        if (String.Equals(provider.Attributes["bridge"], bridgeUrl) == false)
                        {
                            provider.Attributes["bridge"] = bridgeUrl;

                            var key = meta["key"];
                            var pdomain = provider["domain"];
                            if (String.IsNullOrEmpty(pdomain) || pdomain.StartsWith(key))
                            {
                                provider.Attributes["domain"] = domain;
                                UMC.ITME.WebServlet.MainDomain = domain;
                            }
                        }

                        provider.Attributes["repost"] = "open";
                        var pc = Reflection.Configuration("assembly") ?? new ProviderConfiguration();
                        pc.Add(provider);
                        Reflection.Configuration("assembly", pc);
                        HttpBridgeClient.Start(new Uri(bridgeUrl));


                    }

                }, e => isBridging = false);
            });


        }
        void LoadNetwork()
        {
            var hosts = Reflection.Configuration("host");
            // if (hosts.Count == 0)
            // {
            //     var http = UMC.Data.Provider.Create("*", "http");
            //     http.Attributes["port"] = "80";
            //     hosts.Add(http);
            //     var ssl = UMC.Data.Provider.Create("ssl", "https");
            //     ssl.Attributes["port"] = "443";
            //     hosts.Add(ssl);
            //     Reflection.Configuration("host", hosts);
            // }


            var logSb = new StringBuilder();
            logSb.Append(this.Config(hosts));
            var writer = new System.IO.StringWriter(logSb);
            UMC.Data.Sql.Initializer.Register(writer, new UMC.Data.Entities.Initializer(), new UMC.ITME.Entities.Initializer());
            writer.Flush();
            this.StartMsg = logSb.ToString();
        }
        static String Pool()
        {
            var _pool = Net.NetProxy.Pool;
            var sb = new StringBuilder();
            var ps = _pool.Values.ToArray();
            sb.AppendLine("Http Pools:");
            if (ps.Length == 0)
            {
                sb.AppendLine("\t\tEmpty");
            }
            else
            {
                foreach (var p in ps)
                {
                    sb.AppendFormat("{0}\t\t{2}\t\t{1}", p.Unwanted.Count, p.Key, p.BurstError);
                    sb.AppendLine();
                }
            }

            sb.AppendFormat("Http:{0}", httpMimes.Count);// p.Unwanted.Count, p.Key, p.BurstError);
            sb.AppendLine();
            // ThreadStaticAttribute.
            // ThreadStaticAttribute.L
            return sb.ToString();
        }
        public static int Stop(Span<byte> ip, Span<byte> finger)
        {
            int count = 0;

            var ms = httpMimes.Values.ToArray();
            foreach (var m in ms)
            {
                if (finger.SequenceEqual(m.Finger.Span) && ip.SequenceEqual(m.RemoteIpAddress.Span))
                {
                    count++;
                    m.Stop();
                }
            }
            return count;
        }
        static void CheckLink()
        {
            var time = UMC.Data.Utility.TimeSpan();
            var ms = httpMimes.Values.ToArray();

            foreach (var b in ms)
            {
                try
                {

                    if ((b.ActiveTime + b.TimeOut) < time)
                    {
                        httpMimes.TryRemove(b.Id, out _);
                        b.CheckTimeOut();
                    }
                }
                catch
                {

                }
            }
            var ws = Host.HttpWebSocket.WebSockets.ToArray();
            foreach (var w in ws)
            {
                try
                {
                    if (w.ActiveTime + 60 < time)
                    {
                        w.Ping();

                    }
                }
                catch
                {

                }
            }

        }

        void IDoWorker.DoWork()
        {
            // this.Cert();
            try
            {
                var tl = UMC.ITME.DataFactory.Instance().SiteConfig();
                foreach (var t in tl)
                {
                    t?.IsCheck();
                }
            }
            catch (Exception ex)
            {
                Utility.Error("Server", DateTime.Now, ex.Message);
            }
            Register(3600, this);
        }

        void IStringSubscribe.Subscribe(string message)
        {

            UMC.ITME.WebServlet.DomainUnion = (UMC.Data.WebResource.Instance().Provider["union"] ?? ".")[0];
            UMC.ITME.WebServlet.MainDomain = UMC.Data.WebResource.Instance().Provider["domain"] ?? "localhost";
            Load(UMC.Data.Reflection.Configuration("host"));

            Utility.SyncClient(0x00);
        }

        internal static ConcurrentDictionary<int, HttpMime> httpMimes = new ConcurrentDictionary<int, HttpMime>();


        const string PrivateKey = @"-----BEGIN RSA PRIVATE KEY-----
MIIEowIBAAKCAQEAwqNWSHCnMNBI/7Pxmikm3/LdlJVX9AAIaPRDAghtISHAmJgl
t2L8KtQ6AcgECQy5DftU+fUjS/btPAskb9MxVIARv0UbGVKECgYtLIfhjfzI62nk
vO+eDBIBCDlSuR0I64pqvi9d5Q53wag0pbyQ1Car3IDe8yHQHj2EqJHGLVcVh7MG
TeTfjjsBCjpaPBlmVpTCZ28CaePmYyqEcuIGgBK0SxI/abkzNyTL9iwvxj6h9JEw
u1AXvOiXIIIzgglNTjET5yGYiNPfcTF6QpZEblQjrT4CTBR2RiIK0nT2D73h+ugx
xacF6xE2OmRa8vXEggHwcLtUtr1KM2Xhyx4DRQIDAQABAoIBACtwzxod4oLXieNg
IwU4OA/1oZS+/EFeHIJoOehjPxAM+3JTSt+yPPvGICgznwryBv9i3+Vl2/nhY7Np
/TjkFvd4Gf3pi5HMQ+IE3OI6dZH+IE3CdaXhiRHClu5h9N+R5mLDou1NnxQ3dW0I
gK+Y9W4UL3loXdo/6rZFHq2M04FcsYbEUwP0MLnaiVnX/h36du4YCncODWThatqP
8ALuRUm8sa4VyZsCZGGxz1UGAaRr9CK0asDuaDBa35YJpF941EIkFTi5bMBbykob
fkuR/VmFI3hGiMIncVFgBnp9fcuU88jQb8WBoLaYre4wa9NNvbCey/BslZQUuUYl
YJOaDeUCgYEA7KYbsTmmzVjlzfjy03U99oS2WtcmIBexGMEawLGGcjlhpUfSynEu
0m8L8ri+lY3ib196Ru0Em69fMcEYsSSf6LdZI5XMzOT2/7hFIsJd0uewsSDbiS1N
+i4zTdx7N2ycCi9HUHYfFy9W4iFUS2UzhDUwQIPuLnQy/udQbJG37s8CgYEA0o3L
dO144g9U5fuJOq3atAzDWrcurQdvCCjh2OHjh6y13Ua1nhYZ6/AD9+f6YDqbgneJ
YpSJLTYI82JvnDaSTK6j3ULzbJdW5zcHLsFf/8W06h0tehIeMia3NQy6gWEemUPq
PN0vKL+E1WL3jtCSMO1We098PPu0brSuYG6uUasCgYAVuhZ2ygU/ezb2FzIsKep7
dKnNY01zytkOncQYBvSCDjSh2RtITOXwmhNtwHp2/qTYdtqiIma26H4D8meS8/re
gd7kPn+kHC11QvTOASxeDbmSOaMOUCOFobJCJskFSKp24OpaP84Q8d63OjokBfGZ
5Mw+UB6RE0gPUSt4HFTXzwKBgDnV/TcnK/dcosNxrqZRryuZ/edjPg0FZ7hkEnWS
xv8zr9kSXT0JcSFgEpb8P8hDEQhrcW+EwZGLsDW6qlHMo68woY5bn6YKhDKK6Qws
zgPh+On+DcnkRCsee2C1GF4FoXQUNbl2QEf/I6vBvaKbJC0QZJsGoGfX9B4cv3F5
taR1AoGBAIpKbTrtsZ9Fh2fEfu3d8JQ04bgYvqUAAa9G01NSwxNHicPwr9LM95+b
GLqVYCSWVjQ+OeLJRVOUdnFYpJWwXwQYOsfpkLup4mgE0tSOv0MUxRwtdTR7Wukx
5qr++f9yy1BP+N7oP08YjH8byNBhHMkK+NnVqdA0C3JAzZCPOdc8
-----END RSA PRIVATE KEY-----";
        const string CertKey = @"-----BEGIN CERTIFICATE-----
MIICoTCCAYmgAwIBAgIJAO3qL3c6zg9nMA0GCSqGSIb3DQEBCwUAMA8xDTALBgNV
BAMTBGl0bWUwIBcNMjMxMDI2MTEwNTQ2WhgPMjA3MzEwMjYxMTA1NDZaMA8xDTAL
BgNVBAMTBGl0bWUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDCo1ZI
cKcw0Ej/s/GaKSbf8t2UlVf0AAho9EMCCG0hIcCYmCW3Yvwq1DoByAQJDLkN+1T5
9SNL9u08CyRv0zFUgBG/RRsZUoQKBi0sh+GN/MjraeS8754MEgEIOVK5HQjrimq+
L13lDnfBqDSlvJDUJqvcgN7zIdAePYSokcYtVxWHswZN5N+OOwEKOlo8GWZWlMJn
bwJp4+ZjKoRy4gaAErRLEj9puTM3JMv2LC/GPqH0kTC7UBe86JcggjOCCU1OMRPn
IZiI099xMXpClkRuVCOtPgJMFHZGIgrSdPYPveH66DHFpwXrETY6ZFry9cSCAfBw
u1S2vUozZeHLHgNFAgMBAAEwDQYJKoZIhvcNAQELBQADggEBAFcVxZHuswUNJBk5
ZFn7+eIkpLvJ3Zn8y+jznOcJApSOsJ4t9l1Q9K66crwR+TvDHih78hp6jIfIw0NK
+ioXvffHkOqGrv1MHltFsA2fJmM73qOZwY2oOWB3Sxx7bl0D5icfW5BkigOBiXWI
ANMA/uLLjPPMV9xbIXG7jp4cNh5+Fxzo3Xf0FHkURmL1h+hEHD2FpnqAFoUq2ggT
foB4g9Tkmylif13s5+AdEpPTIN6SHUSHTtoTwz447U+rO8/534DeGQziXRsSTMkv
qwKdML5N3W9XcKRWLXXz+cWyf1/f9fED9mW1RzKSgpJORUSh2irbLIZMHlJ5gIP7
xIGN+sg=
-----END CERTIFICATE-----";
    }



}
